package com.mibao.defense;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.IBinder;
import android.os.Parcel;

public class DefenseHostService extends Service {
	
	private static int SERVICE_CONTROLLER_ADD = 0;

	public static String CenterServiceName = "CenterService";          //替换成新的hookService
	private IBinder mCenterService = null;
	public final static int ACTION_GRANT = 0; // 允许
	public final static int ACTION_FORBID = 1; // 禁止
	public final static int ACTION_PROMPT = 2; // 提示
	public final static int ACTION_NO_SET = 3; // 提示
	public static boolean mIsRunning = false;
	
	public HashSet<String> mHideIconAppCache = null;
	
	boolean isshow = true; // 是否弹框，屏幕关闭时不显示为false 正常情况下显示为true
	volatile int ack = -1;
	
	//是否允许卸载返回的
	private static WeakReference<DefenseHostService> sRef;
	/**
	 * 用来解析数据的Descriptor 
	 * */
	public static final String INSTALLER_PKGNAME               =  "com.android.packageinstaller";
	
	IntentFilter mIntentFilter;
	
	private static IDefenseCallback mCallback;
	private static IDefenseMonitor mMonitor;
	
	private static Context mContext;

	public static void start(Context context, IDefenseCallback callback, IDefenseMonitor monitor) {
		if (context == null) {
			LogUtil.e("DefenseService, start, context is null");
			return;
		}
		
		LogUtil.d("DefenseService, start...");
		
		mCallback = callback;
		mMonitor = monitor;
		
		Intent intent = new Intent(context, DefenseHostService.class);// 启动服务
		context.startService(intent);
	}

	public static void stop(Context context) {
		Intent moniter = new Intent(context, DefenseHostService.class);// 启动服务
		context.stopService(moniter);
	}

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}

	@Override
	public void onCreate() {
		LogUtil.d("DefenseService, onCreate...");
		super.onCreate();
		sRef = new WeakReference<DefenseHostService>(this);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		LogUtil.d("DefenseService, onStartCommand...");
		
		mContext = this;
//		if (mIsRunning) {
//			LogUtil.d("mIsRunning true, return");
//			return super.onStartCommand(intent, flags, startId);
//		}
		
		new Thread(new Runnable() {	
			@Override
			public void run() {
				startDefense(mContext, mCallback);
				IBinder binder = DefenseService.getInstance(getApplicationContext(), mMonitor);
				registerSvc(binder);
			}
		}).start();

		mIsRunning = true;
		return START_STICKY;
	}

	public void onDestroy() {
		super.onDestroy();
		mIsRunning = false;
	}

	/**
	 * 把Java服务的指针IBinder传递给CenterService
	 */
	private void registerSvc(IBinder ib) {
		Parcel data = Parcel.obtain();
		Parcel reply = Parcel.obtain();
		try {
			IBinder binder = null;
			for (int i = 0; i < 10; i++) {
				binder = getService(CenterServiceName);// 取得服务
				if (binder == null) {
					Thread.sleep(1000);
				} else {
					break;
				}
			}
			
			if (binder == null) {// 如果c服务没有启动，则退出
				LogUtil.d("binder is null");
				return;
			}
			
			String pkgName = getPackageName();
			PackageManager pm = getPackageManager();
			PackageInfo pi = pm.getPackageInfo(pkgName, 0);
			int uid = pi.applicationInfo.uid;

			data.writeStrongBinder(ib);// 把Ibinder传递给C代理服务
			data.writeString(pkgName);
			data.writeInt(uid);
			binder.transact(SERVICE_CONTROLLER_ADD, data, reply, 0);// 执行远程调用
			
			int result = reply.readInt();
			LogUtil.d("binder is result--" + result);
			if (result != 1)// 如果返回不是1则失败
			{
				return;
			}
		} 
		catch (Exception e) {
		}
		finally {
			data.recycle();
			reply.recycle();
		}
	}

	public static IBinder getService(String svcname) {

		try {
			Class<?> clzServiceManager = Class
					.forName("android.os.ServiceManager");
			Method getService = clzServiceManager.getMethod("getService",
					String.class);
			getService.setAccessible(true);
			return (IBinder) getService.invoke(clzServiceManager, svcname);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;

	}

	/**
	 *  同一个进程内获取 DefenseService
	 */
	public static DefenseHostService get()
	{
		if (sRef != null)
		{
			return sRef.get();
		}
		return null;
	}

	public static void clearCache()
	{
		if (sRef != null)
		{
			DefenseHostService service = sRef.get();
			if (service != null)
			{
				service.mHideIconAppCache = null;
			}
		}
		
	}
	
	/**
	 * 主防对外启动接口
	 * 
	 * 流程：
	 * 1 检查主防是否已经运行，若运行直接返回成功
	 * 2 获取root权限，失败则返回
	 * 3 Inject，Hook
	 * 4 启动Java层服务，并告知system_server中的中心服务
	 * 
	 * 问题：
	 * 1 多线程重入
	 * 2 耗时操作
	 * 3 是否以service方式实现
	 */
	public void startDefense(Context context, IDefenseCallback callback) {
		
		if (context == null) {
			LogUtil.e("Defense starting, param context is null");
			return;
		}
		
		if (callback == null) {
			LogUtil.e("Defense starting, param callback is null");
			return;
		}
		
		// 0 Copy native files from assets to files dir
		try {
			copyAssetFileToFiles(context, "Inject");
			copyAssetFileToFiles(context, "libAppDefense.so");
		} catch (IOException e) {
			e.printStackTrace();
			return;
		}
		LogUtil.d("Copy native files from assets to files dir, Done");
		
		// 1 Defense already started, return success
		if (isRunning()) {
			LogUtil.d("Defense starting, already started");
			callback.onSuccess(null);
			return;
		}
		
		// 2 Get root access
		Process proc;
		try {
			proc = Runtime.getRuntime().exec("su");
		
			OutputStream os = proc.getOutputStream();
			DataOutputStream dos = new DataOutputStream(os);
			
			// 3 Run inject and hook
			String path = context.getFilesDir() + "/Inject";
			LogUtil.d("Defense starting, inject file path is: " + path);
			
			File file = new File(path);
			file.setReadable(true);
			file.setExecutable(true);
			
			String cmd = path + " " + context.getApplicationInfo().nativeLibraryDir + "/libAppDefense.so"
					+ " " + context.getApplicationInfo().uid + " 0";
			LogUtil.d("Defense starting, inject cmd is: " + cmd);
			
			dos.writeBytes(cmd);
			dos.flush();
			os.close();
		} catch (IOException e) {
			e.printStackTrace();
			return;
		}
		
		LogUtil.d("Get root access, inject and hook, Done");
		
//		boolean isRooted = PrivilegeD.getInstance().tryRootNew(context);
//		if (!isRooted) {
//			LogUtil.d("Defense starting, failed to get root access");
//			Bundle bundle = new Bundle();
//			bundle.putString("Error", "获取Root权限失败");
//			callback.onFailure(null);
//			return;
//		}
		
		// TODO Deal with return values
//		PrivilegeD.getInstance().runCmd(cmd);
		try {
			Thread.sleep(8000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		callback.onSuccess(null);
		
		// 4 Start java service, used to communicate with system_server
//		DefenseHostService.start(context, monitor);
	}
	
	public static boolean isRunning() {
		if (getService(CenterServiceName) != null) {
			LogUtil.d("running");
			return true;
		}
		return false;
	}
	
	private void copyAssetFileToFiles(Context context, String filename)
			throws IOException {
		InputStream is = context.getAssets().open(filename);
		byte[] buffer = new byte[is.available()];
		is.read(buffer);
		is.close();
		
		File of = new File(context.getFilesDir() + "/" + filename);
		of.createNewFile();
		FileOutputStream os = new FileOutputStream(of);
		os.write(buffer);
		os.close();
	}
	
	public static void setAppIconHidden(String packageName, boolean isHide) {
		try {
			HashSet<String> names = new HashSet<String>();  
			PackageManager packageManager = mContext.getPackageManager();  
			
			Intent intent = new Intent(Intent.ACTION_MAIN);  
			intent.addCategory(Intent.CATEGORY_HOME);  
			List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,  
					PackageManager.MATCH_DEFAULT_ONLY);  
			for(ResolveInfo ri : resolveInfo){  
				names.add(ri.activityInfo.packageName);  
			} 
			
			if (!names.isEmpty())
			{			
				for (String homePkg : names)
				{					
					Intent removeIntent = new Intent(
							isHide ? Intent.ACTION_PACKAGE_REMOVED : Intent.ACTION_PACKAGE_ADDED, 
							Uri.fromParts("package", packageName, null));
					removeIntent.putExtra(Intent.EXTRA_REPLACING, false);
					removeIntent.setPackage(homePkg);
					mContext.sendBroadcast(removeIntent);
				}
				LogUtil.e("fu", "有桌面 隐藏方式  "+" " + packageName);
			}else {
				Intent newIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED, Uri.fromParts("package", packageName, null));
				newIntent.putExtra(Intent.EXTRA_REPLACING, false);
				newIntent.putExtra("android.intent.extra.user_handle", 0);
				newIntent.putExtra("android.intent.extra.changed_component_name_list", new String[1]);
				mContext.sendBroadcast(newIntent);
				LogUtil.e("fu", "没有桌面 隐藏图标 "+ packageName);
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}